using System;
using SharpWind.Resources;
using Microsoft.Xna.Framework.Content;
using System.Reflection;
using SharpWind.Helpers;
using System.IO;
using System.Xml;
using System.Collections.Generic;

namespace SharpWind.Scripting
{
	public class Script : Resource
	{
		private Assembly assembly = null;

		private List<string> references = new List<string>();

		private string sourceCode = string.Empty;

		private string startupObject = string.Empty;

		public Script( string script )
		{
			if( string.IsNullOrEmpty( script ) )
			{
				throw new ArgumentNullException( "script" );
			}

			ParseScriptFile( Path.Combine( Directories.Scripts, script ) );
		}

		private void ParseScriptFile( string path )
		{
			if( !File.Exists( path ) )
			{
				throw new FileNotFoundException( "path" );
			}

			XmlDocument document = new XmlDocument();
			document.Load( path );

			XmlNode node = document.SelectSingleNode( "/script" );
			if( node != null )
			{
				foreach( XmlNode n in document.SelectSingleNode( "/script/references" ) )
				{
					this.references.Add( n.Attributes[0].Value );
				}

				XmlNode obj = document.SelectSingleNode( "/script/startup/object" );
				this.startupObject = obj.Attributes[0].Value;

				XmlNode code = document.SelectSingleNode( "/script/code" );
				if( code != null )
				{
					this.sourceCode = code.FirstChild.Value;
				}
			}
		}

		private void Compile()
		{
			this.assembly = ScriptCompiler.DefaultCompiler.Compile( this.references.ToArray(), this.sourceCode );
		}

		public object Execute()
		{
			return Execute( null );
		}

		public object Execute( object[] parameters )
		{
			if( this.assembly == null )
			{
				Compile();
			}

			if( this.assembly != null )
			{
				return this.assembly.GetType( this.startupObject ).GetMethod( "ScriptMain" ).Invoke( null, parameters );
			}

			return null;
		}

		internal override void LoadContent( ContentManager contentManager )
		{
			if( this.assembly == null )
			{
				Compile();
			}
		}
	}
}
